package com.tt.job.manage.controller;

import com.tt.job.api.schedule.JobSchedule;
import com.tt.job.api.schedule.ScheduleType;
import com.tt.job.api.schedule.async.AsyncJobSchedule;
import com.tt.job.api.schedule.event.EventJobSchedule;
import com.tt.job.api.schedule.triger.TriggerJobSchedule;
import com.tt.job.common.util.JsonUtil;
import com.tt.job.manage.dto.Response;
import com.tt.job.service.JobEventProduceService;
import com.tt.job.zookeeper.ZookeeperRegistryCenter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/schedule")
public class ScheduleManagerController {
    private final static Logger logger = LoggerFactory.getLogger(ScheduleManagerController.class);
    @Autowired
    JobEventProduceService produceService;
    @Autowired
    ZookeeperRegistryCenter registryCenter;

    /**
     * 添加调度
     *
     * @param type     调度类型
     * @param group    调度分组
     * @param name     调度名称
     * @param jobClass 调度对应的执行job class
     * @param request
     * @return
     */
    @RequestMapping(path = "/add", method = RequestMethod.POST)
    public Response<JobSchedule> addJobSchedule(String type, String group, String name, String jobClass, HttpServletRequest request) {
        JobSchedule schedule;
        switch (type.toLowerCase()) {
            case "trigger":
                String cron = request.getParameter("cron");
                schedule = new TriggerJobSchedule(cron);
                schedule.setType(ScheduleType.TRIGGER);
                break;
            case "async":
                schedule = new AsyncJobSchedule();
                schedule.setType(ScheduleType.ASYNC);
                break;
            case "event":
                String event = request.getParameter("event");
                schedule = new EventJobSchedule(event);
                schedule.setType(ScheduleType.EVENT);
                break;
            default:
                return new Response<>(Response.ReturnCode.PARAMETER_ERROR);
        }
        schedule.setEnabled(true);
        schedule.setGroup(group);
        schedule.setName(name);
        schedule.setJobClass(jobClass);
        String parameters = request.getParameter("parameters");
        if (StringUtils.isNotEmpty(parameters)) {
            schedule.setJobParameters(JsonUtil.decode2MapString(parameters));
        }
        String key = request.getParameter("key");
        if (StringUtils.isNotEmpty(key)) {
            schedule.setKey(key);
        }
        int delayLevel = 0;
        String delay = request.getParameter("delay");
        if (StringUtils.isNotEmpty(delay)) {
            delayLevel = Integer.parseInt(delay);
        }
        schedule.setRetryDelayLevel(delayLevel);
        registryCenter.addJobSchedule(schedule);

        return new Response<>(schedule);
    }

    /**
     * 发起异步任务，如果系统中没有建立对应的异步调度，即使需要执行的任务存在也不会触发
     *
     * @param group      调度分组 需要发起的异步执行的
     * @param jobClass   调度的jobClass 需要发起异步执行的
     * @param key        唯一标识一个需要顺序处理的任务的值（例如：订单的订单id）
     * @param delayLevel 默认0 表示不延迟，消息延迟级别为：1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h 级别从1开始，如级别为3表示延迟10s执行
     * @param parameters body中传递的json格式的参数，此参数将写入context的属性中
     * @return
     */
    @RequestMapping(path = "/async", method = RequestMethod.POST)
    public Response<String> asyncJob(String group, String jobClass, Integer delayLevel, String key, @RequestBody Map<String, String> parameters) {
        //通过registerCenter了解是否存在指定调度
        //参数处理
        //发送调度事件
        if (delayLevel == null) {
            delayLevel = 0;
        }
        String result = produceService.asyncSchedule(group, jobClass, key, delayLevel, parameters);
        if (result != null) {
            logger.debug("异步事件通知到job。 group:{}, jobClass:{}, delayLevel:{}, parameter:{}", group, jobClass, delayLevel, parameters);
            //返回此次事件通知的任务列表
            return new Response<>(Response.ReturnCode.SUCCESS, result);
        }
        return new Response<>(Response.ReturnCode.FAILED, null);

    }

    /**
     * 删除指定的调度信息
     *
     * @param type  调度类型
     * @param group 调度分组
     * @param name  调度名称
     * @return
     */
    @RequestMapping(path = "/delete", method = RequestMethod.POST)
    public Response<JobSchedule> deleteJobSchedule(String type, String group, String name) {
        registryCenter.deleteSchedule(type.toUpperCase(), group, name);
        return new Response<>(Response.ReturnCode.SUCCESS);
    }

    /**
     * 获取所有调度列表
     *
     * @return
     */
    @RequestMapping("/list")
    public Response<List<JobSchedule>> getSchedules() {
        List<JobSchedule> jobSchedules = registryCenter.getJobSchedules();
        return new Response<>(jobSchedules);
    }

    /**
     * 发送事件
     *
     * @param group      事件分组
     * @param event      事件名称
     * @param key        唯一标识一个需要顺序处理的任务的值（例如：订单的订单id）
     * @param parameters 事件附带的参数，将写入context的属性中, 应当在body中传递，json格式
     * @return
     */
    @RequestMapping(value = "/event", method = RequestMethod.POST)
    public Response<List<String>> sendEvent(String group, String event, String key, @RequestBody Map<String, String> parameters) {
        //通过registerCenter了解当前有哪些事件调度关注了该事件，获得job列表
        //针对job列表发送job的执行通知事件
        List<String> result = produceService.eventSchedule(group, event, key, parameters);
        if (result != null) {
            if (result.size() == 0) {
                logger.warn("事件没有通知任何job。 group:{}, event:{}, parameter:{}", group, event, parameters);
            }
            //返回此次事件通知的任务列表
            return new Response<>(result);
        }
        return new Response<>(Response.ReturnCode.FAILED);
    }
}
